﻿using EBA.IoC;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using EBA.Dynamic;

namespace EBA.Framework
{
    /// <summary>
    /// 独立AppDomain中的线程，用于启动<see cref="RemotingBundle{T}"/>
    /// </summary>
    [Serializable]
    public class RemotingBundleFactory : MarshalByRefObject
    {
        /// <summary>
        /// IoC容器
        /// </summary>
        IContainer _Container;


        public string StartupPath { get; set; }

        /// <summary>
        /// IoC容器
        /// </summary>
        protected virtual IContainer Container
        {
            get
            {
                if (_Container == null)
                {
                    //  Debugger.Launch();
                    var config = new ContainerConfiguration();

                    config.WithAssemblies(WindowsAssembly.GetAssemblies(this.StartupPath,"*.dll"));

                    _Container = config.CreateContainer();
                }

                return _Container;
            }
        }

        /// <summary>
        /// 创建远程插件对象
        /// </summary>
        /// <typeparam name="TBundle">自定义插件类型</typeparam>
        /// <param name="runtime">运行时</param>
        /// <param name="bundleId">插件标识</param>
        /// <returns></returns>
        public RemotingBundle CreateRemotingBundle<TBundle>( string runtime, string bundleId) where TBundle : IBundle
        {
            return CreateRemotingBundle(typeof(TBundle), runtime, bundleId);
        }




        public RemotingBundle CreateRemotingBundle(Type type, string runtime, string bundleId)
        {
            AutoResetEvent syncEvent = GetSyncEvent(runtime, bundleId);

            try
            {
                var bundle = this.Container.GetExport(type, bundleId)  as IBundle;
                bundle.StartupPath = AppRuntime.ApplicationPath;

                var remotingBundle = bundle.DynamicCastTo(type, typeof(RemotingBundle)) as RemotingBundle;

                remotingBundle.Initialize(bundle);
                remotingBundle.RegisterChannels(runtime, bundleId);

                // var dynamicContext = remotingBundle as IDynamicContext;

                return remotingBundle;
            }
            finally
            {
                syncEvent.Set();
            }
        }

        /// <summary>
        /// 获取同步对象
        /// </summary>
        /// <param name="runtime"></param>
        /// <param name="bundleId"></param>
        /// <returns></returns>
        private static AutoResetEvent GetSyncEvent(string runtime, string bundleId)
        {
            var syncEventUri = RemotingUris.BuildFullRuntimeSyncEventUri(runtime, bundleId);

            AutoResetEvent syncEvent = (AutoResetEvent)Activator.GetObject(typeof(AutoResetEvent), syncEventUri);
            return syncEvent;
        }
    }
}
